﻿//Copyright (C) <2013>  <jonathan cleeve norton> All Rights Reserved 
//Contact jon.norton@fin-plus.co.uk website <http://www.fin-plus.co.uk/>
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Data;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Imaging;
using System.Windows.Shapes;
using System.Windows.Interop;
using System.Windows.Threading;
using System.Threading;
using System.Reflection;
using System.Diagnostics;
using FinPlusDBConn;
using FinPlusCommon;
using Messaging2;
using Microsoft.Practices.Prism.Mvvm;
using log = Logger.Logger;
using u = FinPlusUtility.Utility;

namespace FinPlusWPFControls
{
    public partial class FinPlusView : FinPlusControl, IView
    {
        public override string Id { get { return _id == null ? "View" : _id; } set { _id = value; } }
        public override string[] States { get { return new string[] { "Height", "Width", "Left", "Top", "TabPosition", "ScaleValue", "RotateAngle" }; } }
        public override string[] TestStates { get { return new string[] { "ModelTest", "ChildrenCount", "Height", "Width", "Left", "Top" }; } }
        public override IFinPlusFunctions Model { get { return _app.Model; } }
        public override string ModelTest { get { return Model.ToString(); } }
        public override bool IsValid { get; set; }
 
        public int ChildrenCount { get { return grid.Children.Count; } }
        public double TabPosition { get { return padding.Width; } set { padding.Width = value; } }
        public double ScaleValue { get { return _transform.ScaleValue; } set { _transform.ScaleValue = value; } }
        public double RotateAngle { get { return _transform.RotateAngle; } set { _transform.RotateAngle = value; } }

        public string Guid;

        private const string XmlNode = "root/current";
        private enum DockControls { FinPlusControl, Default }
        private FinPlusControl _app;
        private FinPlusTransform _transform;
        private IFinPlusFunction _func;
        private ITransport _tran;
        private string _id, _user;
        private string  _configPath;

        //construct
        public FinPlusView(string configPath, string name)
        {
            InitializeComponent();
            Initialise();
            Load(_configPath = configPath, Name);
        }

        public FinPlusView()
        {
            InitializeComponent();
            Initialise();
        }

        //common control interface
        public override void Dock(object control, string dock)
        {
            try
            {
                switch (u.EnumTryParse<DockControls>(control.GetType().BaseType.Name, DockControls.Default))
                {
                    case DockControls.FinPlusControl: AddControl((FinPlusControl)control, dock); break;
                    case DockControls.Default: grid.Children.Add((UserControl)control); break;
                }
            }
            catch (Exception e)
            {
                IsValid = log.Log(Logger.Level.Error, e.Message, e);
                grid.Children.Add(new FinPlusErrorDisplay(e));
            }
        }

        public override void CommandRouter(IFinPlusFunction func)
        {
            try
            {
                if (_app != null)
                    _app.CaptureCommand(func);

                switch ((Commands)Enum.Parse(typeof(Commands), func.Name, true))
                {
                    case Commands.Close: Dispose(); break;
                    case Commands.Save: Save(); break;
                    case Commands.Load: LoadState(); break;
                    default: throw new Exception(string.Format("event not recognised {0}", func.Name));
                }
            }
            catch (Exception e)
            {
               IsValid = log.Log(Logger.Level.Error, e.Message, e);
            }
        }

        public override void Dispose()
        {
            try
            {
                if (_tran != null)
                {
                    _tran.Listener.Stop(Guid);
                    _tran.Publish(new Message(Guid, "OnClose"));
                }
                if (_app != null)
                    _app.Dispose();
            }
            catch (Exception e)
            {
                log.Log(Logger.Level.Error, e.Message, e);
            }
        }

        public override void Initialise()
        {
            scalebar.Children.Add(_transform = new FinPlusTransform());
            _user = Environment.UserName;
        }

        //public
        public void Load(string configPath, string returnFunction,  string guid = "", bool isDialog = false, string parms = "")
        {
            try
            {
                _configPath = configPath;
                Guid = guid;

                u.Env env;
                var config = u.ConfigXml(configPath + ".config", out env);

                EventListen(config);
                Build(configPath, returnFunction, parms, env);
                LoadState();
            }
            catch (Exception e)
            {
                log.Log(Logger.Level.Warning, e.Message, e);
            }
        }

        public void Save()
        {
            var funcsState = FinPlusAssembler.ExtractState(_func, Environment.UserName);
            funcsState.ToXmlDoc(XmlNode).Save(_configPath + ".State");
        }

        //private
        private void AddControl(FinPlusControl control, string dock)
        {
            _configPath = u.GetAssemblyPath(Assembly.GetExecutingAssembly()) + "FinPlusClients\\" + dock;
            _app = new FinPlusApplication();
            _app.Dock(control, string.Empty);
            grid.Children.Add(_app);
            LoadState();
        }

        private void SetTitle(string title)
        {
            titleText.Text = title;
        }

        private void Build(string configPath, string returnFunction, string parms, u.Env env = u.Env.unknown)
        {
            _configPath = configPath;
            titleText.Text = returnFunction;

            grid.Children.Add(_app = new FinPlusApplication(configPath, returnFunction, parms, env));
        }

        private void LoadState()
        {
            try
            {
                _func = new Function("FinPlusView", "finPlusView", Environment.UserName) { Object = this };
                FinPlusAssembler.InjectState(_func, new Functions(_configPath + ".state", XmlNode));
            }
            catch (Exception e)
            {
                log.Log(Logger.Level.Warning, e.Message, e);
            }
        }

        private void EventListen(u.Config config)
        {
            _tran = new Transport(config["localmessagingsettings"]["address"], int.Parse(config["localmessagingsettings"]["port"]));
            _tran.Listener.MessageRecieved += EventMessage;
            _tran.Listen(Guid);
        }

        //cmds
        private new enum Commands { Close, Save, Load}

        //events
        public void Command_OnInject(object sender, FunctionEventArgs a) { this.Dispatcher.Invoke(DispatcherPriority.Normal,(Action)(() => { CommandRouter(a.Function); })); }
        private void Window_OnSave(object sender, RoutedEventArgs a) { CommandRouter(new Function(Commands.Save.ToString(), Id, _user)); }
        private void Window_OnLoad(object sender, RoutedEventArgs a) { CommandRouter(new Function(Commands.Load.ToString(), Id, _user)); }
        private void Key_Click(object sender, KeyEventArgs a)
        {
            if (a.Key == Key.S && Keyboard.Modifiers == ModifierKeys.Control)
                CommandRouter(new Function(Commands.Save.ToString(), Id, _user));
        }
        private void EventMessage(object sender, EventArgs a)
        {
            var func = new Function(((MessageEventArgs)a).Message.Value.ToString(), Id, _user);
            if (!CheckAccess())
                Dispatcher.Invoke(() => CommandRouter(func));
            else
                CommandRouter(func);
        }
    }
}
